/**
 * 
 */
package cu.ds.logicalsync.fytasrealm.communication;


import java.util.Set;

import cu.ds.logicalsync.fytasrealm.communication.event.MapStatusEvent;
import cu.ds.logicalsync.fytasrealm.communication.event.MapStatusListener;
import cu.ds.logicalsync.fytasrealm.communication.event.PeerStatusEvent;
import cu.ds.logicalsync.fytasrealm.communication.event.PeerStatusListener;
import cu.ds.logicalsync.fytasrealm.communication.event.WorldStatusEvent;
import cu.ds.logicalsync.fytasrealm.communication.event.WorldStatusListener;
import cu.ds.logicalsync.fytasrealm.communication.model.PeerInfo;
import cu.ds.logicalsync.fytasrealm.model.Map;
import cu.ds.logicalsync.fytasrealm.model.Warrior;
import cu.ds.logicalsync.fytasrealm.model.World;
import cu.ds.logicalsync.fytasrealm.util.Tools;

/**
 * Facade for all communication services
 * 
 * @author r.vashira
 */
public class Network {
	/** Member Variables **/
	private String clientName;
	
	/** Services Stack **/
	private JxtaConnection connection;
	private PeerStatusService peerStatusService;
	private MapStatusService mapStatusService;
	private WorldStatusService worldStatusService;
	
	/** Event Observers **/
	private PeerStatusEventObserver peerStatusListener;
	private MapStatusEventObserver mapStatusListener;
	private WorldStatusEventObserver worldStatusListener;
	
	/** Properties **/
	private boolean isStartBg; // for debugging
	private World myWorld;
	private Map currentMap;
	private Warrior myWarrior;
	/**
	 * @return the myWorld
	 */
	public World getMyWorld() {
		return myWorld;
	}
	/**
	 * @param myWorld the myWorld to set
	 */
	public void setMyWorld(World myWorld) {
		this.myWorld = myWorld;
		
		updateCurrentWorldToServices();
	}
	/**
	 * @return the currentMap
	 */
	public Map getCurrentMap() {
		return currentMap;
	}
	/**
	 * @param currentMap the currentMap to set
	 */
	public void setCurrentMap(Map currentMap) {
		this.currentMap = currentMap;
		
		updateCurrentMapToServices();
	}
	/**
	 * @return the myWarrior
	 */
	public Warrior getMyWarrior() {
		return myWarrior;
	}
	/**
	 * @param myWarrior the myWarrior to set
	 */
	public void setMyWarrior(Warrior myWarrior) {
		this.myWarrior = myWarrior;
	}
	
	/***************** Update Changes to Services *****************/
	private void updateCurrentMapToServices() {
		mapStatusService.setMyMap(this.currentMap);
	}
	
	private void updateCurrentWorldToServices() {
		mapStatusService.setMyWorld(this.myWorld);
	}
	
	
	/**
	 * Get instance of JxtaConnection
	 * 
	 * @return the connection
	 */
	public JxtaConnection getConnection() {
		return connection;
	}
	
	/**
	 * Get instance of PeerStatusService for 
	 * <ul>
	 * <li>Method calling</li>
	 * <li>Register Event Listener</li>
	 * </ul> 
	 * @return the peerStatusService
	 */
	public PeerStatusService getPeerStatusService() {
		return peerStatusService;
	}
	
	/**
	 * Get instance of MapStatusService for 
	 * <ul>
	 * <li>Method calling</li>
	 * <li>Register Event Listener</li>
	 * </ul> 
	 * @return the mapStatusService
	 */
	public MapStatusService getMapStatusService() {
		return mapStatusService;
	}

	/**
	 * Get instance of WorldStatusService for 
	 * <ul>
	 * <li>Method calling</li>
	 * <li>Register Event Listener</li>
	 * </ul> 
	 * @return the mapStatusService
	 */
	public WorldStatusService getWorldStatusService() {
		return worldStatusService;
	}
	
	/**
	 * Create Network Facade with given client name
	 * @param clientName
	 */
	public Network(String clientName) {
		this(clientName, true);
	}
	
	public Network(String clientName, boolean isStartBgService) {
		super();
		this.clientName = clientName;
		this.isStartBg = isStartBgService;
		
		initializeServices();
		initializeObservers();
	}

	private void initializeServices() {
		// Initial JxtaConnection which is primary element
		this.connection = JxtaConnection.getInstance(clientName);
		
		this.peerStatusService = new PeerStatusService(connection);
		this.mapStatusService = new MapStatusService(connection);
		this.worldStatusService = new WorldStatusService(connection);
		// TODO: Add more services here
		
	}
	
	private void initializeObservers() {
		peerStatusListener = new PeerStatusEventObserver();
		mapStatusListener = new MapStatusEventObserver();
		worldStatusListener = new WorldStatusEventObserver();
		
		// Register event listener
		peerStatusService.addListener(peerStatusListener);
		mapStatusService.addListener(mapStatusListener);
		worldStatusService.addListener(worldStatusListener);
	}
	
	/************* Public Methods **************/
	
	/**
	 * Start the Network
	 */
	public void start() {
		// JxtaConnection started already in constructor
		/*try {
			connection.goOnline();
		} catch (CommunicationException e) {
			// TODO log.error(e);
			e.printStackTrace();
		}*/
		
		// TODO: Start more services here
		if(this.isStartBg) {
			peerStatusService.start();
			System.out.println("PeerStatusService - STARTED...");
		}
		mapStatusService.start();
		System.out.println("MapStatusService - STARTED...");
		worldStatusService.start();
		System.out.println("WorldStatusService - STARTED...");
	}
	
	/**
	 * Stop the Network
	 */
	public void stop() {
		connection.goOffline();
		
		// TODO: Stop more services here
		if(this.isStartBg) {
			peerStatusService.stop();
			System.out.println("PeerStatusService - STOPED...");
		}
		mapStatusService.stop();
		System.out.println("MapStatusService - STOPED...");
		worldStatusService.stop();
		System.out.println("WorldStatusService - STOPED...");
	}
	
	
	/************** Anonymous Class *************/
	
	/**
	 * Inner class for handling PeerStatus Events
	 * @author r.vashira
	 */
	protected class PeerStatusEventObserver implements PeerStatusListener {
		
		public PeerStatusEventObserver() {
			//TODO: send args
		}
		
		private void syncPeerList() {
			// TODO: Impl: sync list of peer with other peer. 
			Set<PeerInfo> latestPeersFound = peerStatusService.getPeerCollection();
			mapStatusService.setPeerCollection(latestPeersFound);
		}
		
		/**
		 * {@inheritDoc}  
		 */
		public void newPeerConnected(PeerStatusEvent event) {
			// TODO: Get new peer then sync with other clients
			PeerInfo peerInfo = event.getPeerInfo();
			syncPeerList();
			
			Tools.popInformationMsg("Peer Events", "New Warrior is login to the system: " + peerInfo.getName());
		}
	}
	
	protected class MapStatusEventObserver implements MapStatusListener {

		/**
		 * {@inheritDoc}  
		 */
		public void mapUpdated(MapStatusEvent event) {
			// TODO Auto-generated method stub
			
		}
		
	}

	protected class WorldStatusEventObserver implements WorldStatusListener {

		/**
		 * {@inheritDoc}  
		 */
		public void worldEntered(WorldStatusEvent event) {
			// TODO Auto-generated method stub
			
		}

		public void worldLeaved(WorldStatusEvent event) {
			// TODO Auto-generated method stub
			
		}
		
	}
}
